package com.hsxxherp.simplify.framework.log4j2.filter;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.SimpleMessage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Plugin(name = "PasswordMaskingFilter", category = "Core", elementType = "filter", printObject = true)
public class PasswordMaskingFilter extends AbstractFilter {

    private static final Pattern PASSWORD_PATTERN = Pattern.compile("password\\s*=\\s*([\"']?)([^\"']+)\\1");

    protected PasswordMaskingFilter(Result onMatch, Result onMismatch) {
        super(onMatch, onMismatch);
    }

    @PluginFactory
    public static PasswordMaskingFilter createFilter(
            @PluginAttribute("onMatch") final Result match,
            @PluginAttribute("onMismatch") final Result mismatch) {
        return new PasswordMaskingFilter(match != null ? match : Result.NEUTRAL,
                mismatch != null ? mismatch : Result.NEUTRAL);
    }

    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
        String maskedMsg = maskPassword(msg);
        return super.filter(logger, level, marker, maskedMsg, params);
    }

    @Override
    public Result filter(LogEvent event) {
        String originalMessage = event.getMessage().getFormattedMessage();
        String maskedMessage = maskPassword(originalMessage);

        Log4jLogEvent.Builder builder = new Log4jLogEvent.Builder(event);
        builder.setMessage(new SimpleMessage(maskedMessage));
        LogEvent newEvent = builder.build();

        return super.filter(newEvent);
    }

    private String maskPassword(String message) {
        Matcher matcher = PASSWORD_PATTERN.matcher(message);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String masked = matcher.group(2).replaceAll(".", "*");
            String replacement = "password=" + matcher.group(1) + masked + matcher.group(1);
            matcher.appendReplacement(sb, replacement);
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
}